#ifndef __M_MATCHER_H__
#define __M_MATCHER_H__

#include <list>
#include "util.hpp"
#include "room.hpp"

template <class T>
class match_queue
{
private:
    // 用链表不是queue, 是因为中间删除数据的需要
    std::list<T> _list;
    // 线程安全
    std::mutex _mutex;
    // 主要为了阻塞消费者, 队列中元素不够2阻塞
    std::condition_variable _cond;
public:
    // 获取元素个数
    int size() 
    {
        std::unique_lock<std::mutex>(_mutex);
        return _list.size();
    }
    // 是否为空
    bool empty()
    {
        std::unique_lock<std::mutex>(_mutex);
        return _list.empty();
    }
    // 阻塞线程
    void wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }
    // 入队数据, 并唤醒线程
    void push(const T& data)
    {
        std::unique_lock<std::mutex>(_mutex);
        _list.push_back(data);
        _cond.notify_all();
    }
    // 出队数据
    bool pop(T& data)
    {
        std::unique_lock<std::mutex>(_mutex);
        if (_list.empty() == true)
        {
            return false;
        }

        data = _list.front();
        _list.pop_front();

        return true;
    }
    // 移除指定数据
    bool remove(T& data)
    {
        std::unique_lock<std::mutex> _mutex;
        _list.remove(data);
    }
};

class mather
{
private:
    // 普通选手匹配队列
    match_queue<uint64_t> _q_normal;
    // 高手
    match_queue<uint64_t> _q_high;
    // 大神
    match_queue<uint64_t> _q_super;
    // 三个队列的处理线程
    std::thread _th_normal;
    std::thread _th_high;
    std::thread _th_super;
    room_manager* _rm;
    user_table *_ut;
    online_manager *_om;
private:
    void th_normal_entry() { return handle_match(_q_normal); }
    void th_high_entry() { return handle_match(_q_high); }
    void th_super_entry() { return handle_match(_q_super); }
private:
    void handle_match(match_queue<uint64_t> &queue)
    {
        while (1)
        {
            // 判断人数是否大于2, <2则阻塞等待
            if (queue.size() < 2)
            {
                queue.wait();
            }
            // 走下来代表人数够了, 出队两个玩家
            uint64_t uid1, uid2;
            bool ret = queue.pop(uid1);
            if (ret == false)
            {
                continue;
            }
            ret = queue.pop(uid2);
            if (ret == false)
            {
                this->add(uid1);
                continue;
            }
            // 检验两个玩家是否在线, 如果有人掉线, 则吧另一个重新加入队列
            wsserver_t::connection_ptr con1 = _om->get_con_from_hall(uid1);
            if (con1.get() == nullptr)
            {
                this->add(uid2);
                continue;
            }

            wsserver_t::connection_ptr con2 = _om->get_con_from_hall(uid2);
            if (con2.get() == nullptr)
            {
                this->add(uid1);
                continue;
            }
            // 为两个玩家创建房间, 并将玩家加入房间中
            room_ptr rp = _rm->creat_room(uid1, uid2);
            if (rp.get() == nullptr)
            {
                queue.push(uid1);
                queue.push(uid2);
                continue;
            }
            // 对两个玩家进行响应
            Json::Value resp;
            resp["optype"] = "match_success";
            resp["result"] = true;
            std::string body;
            json_util::serialize(resp, body);
            con1->send(body);
            con2->send(body);
        }
    }

public:
    mather(room_manager *rm, user_table *ut, online_manager *om)
        : _rm(rm), _ut(ut), _om(om),
          _th_normal(std::thread(&mather::th_normal_entry, this)),
          _th_high(std::thread(&mather::th_high_entry, this)),
          _th_super(std::thread(&mather::th_super_entry, this))
    {
        DLOG("游戏匹配模块初始化完毕....");
    }
    ~mather(){}

    bool add(uint64_t uid)
    {
        // 根据玩家天梯分数, 判断玩家档次, 添加到不同的队列
        Json::Value user;
        bool ret = _ut->select_by_id(uid, user);
        if (ret == false)
        {
            DLOG("获取玩家%d失败!", uid);
        }
        int source = user["score"].asInt();
        // 添加到指定的队列中
        if (source < 2000)
        {
            _q_normal.push(uid);
        }
        else if(source >= 2000 && source < 3000)
        {
            _q_high.push(uid);
        }
        else
        {
            _q_super.push(uid);
        }

        return true;
    }

    bool del(uint64_t uid)
    {
        // 根据玩家天梯分数, 判断玩家档次, 添加到不同的队列
        Json::Value user;
        bool ret = _ut->select_by_id(uid, user);
        if (ret == false)
        {
            DLOG("获取玩家%d失败!", uid);
        }
        int source = user["score"].asInt();
        // 添加到指定的队列中
        if (source < 2000)
        {
            _q_normal.remove(uid);
        }
        else if(source >= 2000 && source < 3000)
        {
            _q_high.remove(uid);
        }
        else
        {
            _q_super.remove(uid);
        }

        return true;
    }
};

#endif
